createFunc(PutsFty, PutsFn, "puts", Int32Ty,
{Int8PtrTy});
2. The landingpad instruction is the first instruction we generate. The result type is a structure containing fields of an i8 pointer
and an i32 type. This structure is generated with a call to the StructType::get() function. Moreover, since we need to
handle an exception of a C++ int type, we need to also add this as a clause to the landingpad instruction, which must be a
constant of an i8 pointer type. This means that generating a bitcast instruction is required to convert the TypeInfo value
into this type. After, we must store the value that’s returned from the instruction for later use in the Exc variable:
LandingPadInst *Exc = Builder.CreateLandingPad(
StructType::get(Int8PtrTy, Int32Ty), 1, "exc");
Exc->addClause(
ConstantExpr::getBitCast(TypeInfo, Int8PtrTy));
3. Next, we extract the type selector from the returned value. With a call to the llvm.eh.typeid.for intrinsic, we retrieve the
type ID for the TypeInfo field, representing the C++ int type. With this IR, we have generated the two values we need to
compare to decide if we can handle the exception:
Value *Sel =
Builder.CreateExtractValue(Exc, {1}, "exc.sel");
CallInst *Id =
Builder.CreateCall(TypeIdFty, TypeIdFn,
{ConstantExpr::getBitCast(
TypeInfo, Int8PtrTy)});
4. To generate the IR for the comparison, we must call our createICmpEq() function. This function also generates two basic
blocks, which we store in the TrueDest and FalseDest variables:
BasicBlock *TrueDest, *FalseDest;
createICmpEq(Sel, Id, TrueDest, FalseDest, "match",
"resume");
5. If the two values do not match, the control flow continues at the FalseDest basic block. This basic block only contains a
resume instruction, to give control back to the C++ runtime:
Builder.SetInsertPoint(FalseDest);
Builder.CreateResume(Exc);
6. If the two values are equal, the control flow continues at the TrueDest basic block. First, we generate the IR code to extract the
pointer to the exception from the return value of the landingpad instruction, stored in the Exc variable. Then, we generate a
call to the __cxa_begin_catch () function, passing the pointer to the exception as a parameter. This indicates the beginning
of handling the exception for the runtime:
Builder.SetInsertPoint(TrueDest);
Value *Ptr =
Builder.CreateExtractValue(Exc, {0}, "exc.ptr");
Builder.CreateCall(BeginCatchFty, BeginCatchFn,
{Ptr});
7. The exception is then handled by calling the puts() function to print a message to the console. For this, we generate a pointer to
the string with a call to the CreateGlobalStringPtr() function, and then pass this pointer as a parameter in the generated
call to the puts() function:
Value *MsgPtr = Builder.CreateGlobalStringPtr(
"Divide by zero!", "msg", 0, M);
Builder.CreateCall(PutsFty, PutsFn, {MsgPtr});
8. Now that we’ve handled the exception, we must generate a call to the __cxa_end_catch() function to inform the runtime
about it. Finally, we return from the function with a ret instruction:
Builder.CreateCall(EndCatchFty, EndCatchFn);
Builder.CreateRet(Int32Zero);
}